// import { BenchmarkRunner } from "../../../utils/benchmarkTsSuite";
// declare function print(arg:string) : string;
declare interface ArkTools{
  timeInUs(arg:any):number
}
// Modify n value to change the difficulty of the benchmark
// suggesting using input = 25000000;
const input: number = 250000;

class AminoAcid {
  prob: number = 0.0;
  sym: number = 0;
  constructor(prob: number, sym: number) {
    this.prob = prob;
    this.sym = sym;
  }
}

const IM = 139968;
const IA = 3877;
const IC = 29573;
const SEED = 42;

let n: number = input;
const width: number = 60;

const iub: AminoAcid[] = [
  new AminoAcid(0.27, 97), // "a"),
  new AminoAcid(0.12, 99), // "c"),
  new AminoAcid(0.12, 103), // "g"),
  new AminoAcid(0.27, 116), // "t"),
  new AminoAcid(0.02, 66), // "B"),
  new AminoAcid(0.02, 68), // "D"),
  new AminoAcid(0.02, 72), // "H"),
  new AminoAcid(0.02, 75), // "K"),
  new AminoAcid(0.02, 77), // "M"),
  new AminoAcid(0.02, 78), // "N"),
  new AminoAcid(0.02, 82), // "R"),
  new AminoAcid(0.02, 83), // "S"),
  new AminoAcid(0.02, 86), // "V"),
  new AminoAcid(0.02, 87), // "W"),
  new AminoAcid(0.02, 89), // "Y"),
];

function binarySearch(rnd: number, arr: AminoAcid[]): number {
  let low = 0;
  let high = arr.length - 1;
  for (; low <= high;) {
    let middle = (low + high) >>> 1;
    if (arr[middle].prob >= rnd) {
      high = middle - 1;
    } else {
      low = middle + 1;
    }
  }
  return arr[high + 1].sym;
}

function accumulateProbabilities(acid: AminoAcid[]): void {
  for (let i = 1; i < acid.length; i++) {
    acid[i].prob += acid[i-1].prob;
  }
}

function randomFasta(buffer: number[], acid: AminoAcid[], n: number) {
  let cnt = n;
  accumulateProbabilities(acid);
  let pos = 0;
  let seed = SEED;
  while (cnt > 0) {
    let m = cnt > width ? width : cnt;
    let f = 1.0 / IM;
    let myrand = seed;
    for (let i = 0; i < m; i++) {
      myrand = (myrand * IA + IC) % IM;
      let r = myrand * f;
      buffer[pos] = binarySearch(r, acid);
      pos++;
      if (pos === buffer.length) {
        pos = 0;
      }
    }
    seed = myrand;
    buffer[pos] = 10;
    pos++;
    if (pos === buffer.length) {
      pos = 0;
    }
    cnt -= m;
  }
}

export function RunFastaRandom2() {
  const bufferSize: number = 256 * 1024;
  let buffer = new Array<number>();
  for (let i = 0; i < bufferSize; i++) {
    buffer.push(10);
  }
  const homosapiens: AminoAcid[] = [
    new AminoAcid(0.3029549426680, 97), // "a"),
    new AminoAcid(0.1979883004921, 99), // "c"),
    new AminoAcid(0.1975473066391, 103), // "g"),
    new AminoAcid(0.3015094502008, 116), // "t"),
  ];
  let start = ArkTools.timeInUs();
  randomFasta(buffer, homosapiens, 5*n);
  let end = ArkTools.timeInUs();
  let time = (end - start) / 1000
  print("Array Access - RunFastaRandom2:\t"+String(time)+"\tms");
  return time;
}
RunFastaRandom2()
// let runner3 = new BenchmarkRunner("Array Access - RunFastaRandom2", RunFastaRandom2);
// runner3.run();
